package opengl.program;

import static org.lwjgl.opengl.GL11.GL_FALSE;
import static org.lwjgl.opengl.GL20.GL_INFO_LOG_LENGTH;
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glBindAttribLocation;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glDeleteShader;
import static org.lwjgl.opengl.GL20.glDetachShader;
import static org.lwjgl.opengl.GL20.glGetAttribLocation;
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
import static org.lwjgl.opengl.GL20.glGetProgrami;
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glUseProgram;

import java.util.Map;

public class GLProgram {
	protected int program;

	public GLProgram(){
		program = glCreateProgram();
	}
	
	protected void initShaders(int... shaders) {
		for (int shader : shaders) {
			if (shader != -1) {
				glAttachShader(program, shader);
			}
		}
		glLinkProgram(program);

		if (glGetProgrami(program, GL_LINK_STATUS) == GL_FALSE) {
			throw new RuntimeException("Failure in linking program. Error log:\n" + glGetProgramInfoLog(program, glGetProgrami(program, GL_INFO_LOG_LENGTH)));
		}

		for (int shader : shaders) {
			glDetachShader(program, shader);
		}

		for (int shader : shaders) {
			glDeleteShader(shader);
		}
	}

	public void bindAttribution(Map<Integer, String> attributes) {
		if (attributes == null) {
			return;
		}
		
		for (int i : attributes.keySet()) {
			glBindAttribLocation(program, i, attributes.get(i));
		}
	}

	public int getUniformLocation(String name) {
		return glGetUniformLocation(program, name);
	}
	
	public int getAttribLocation(String name) {
		return glGetAttribLocation(program, name);
	}

	public void begin() {
		glUseProgram(program);
	}

	public void end() {
		glUseProgram(0);
	}
}
